package com.spider.admin.init;

import com.spider.admin.conf.ENVConf;
import com.spider.admin.utils.OSCommandUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import java.io.*;
import java.net.Inet4Address;
import java.net.InterfaceAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Enumeration;

@Slf4j
@Component
public class AgentServerT {

    @Autowired
    private ENVConf envConf;

    public void startAgent() {
        try {
            if (OSCommandUtil.hasRunPort(envConf.getUiRunPort())) {
                throw new Exception("ui 端口(" + envConf.getUiRunPort() + ")已经占用");
            }
            String[] excFileInfos = findAgentExeFile();
            OSCommandUtil.executeCmd(excFileInfos[0], " start " + excFileInfos[1], false, false);
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage() + "----代理服务启动失败");
        }
    }

    public void stopAgent() {
        try {
            int i = stopAgentServer();
            if (i == 3) {
                throw new Exception("代理关闭异常");
            }
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage() + "----代理服务关闭失败");
        }
    }

    @Async
    public void reloadAgent() {
        try {
            int i = reStartAgentServer();
            if (i != 1) {
                throw new Exception("代理重启失败");
            }
            log.info("成功重启代理服务");
        } catch (Exception e) {
            log.error("重启代理服务异常" + e.getMessage());
            throw new RuntimeException(e.getMessage());
        }
    }

    public void testAgentConf() {
        try {
            String[] batPath = findAgentExeFile();
            if (batPath == null || batPath.length != 2) {
                throw new Exception("代理启动文件不存在");
            }
            ProcessBuilder processBuilder = new ProcessBuilder();
            processBuilder.directory(new File(batPath[0]));
            processBuilder.command(batPath[1], "-s", "reload");
            Process process = processBuilder.start();
            int i = process.waitFor();
            log.info("代理服务关闭");
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage() + "----代理服务关闭失败");
        }
    }

    /**
     * 跨平台启动nginx
     *
     * @throws IOException
     */
    private void startProc() throws Exception {
        if (OSCommandUtil.isWinOS()) {
            startWinProc();
        } else {
            startLinuxProc();
        }
    }

    /**
     * 获取Nginx代理系统目录和可执行文件
     *
     * @return
     */
    private String[] findAgentExeFile() {
        String[] strs = new String[2];
        strs[0] = envConf.getUiContainerBasePath();
        ;
        if (OSCommandUtil.isWinOS()) {
            strs[1] = "nginx.exe";
        } else {
            strs[0] = strs[0] + "\\bin";
            strs[1] = "openrestry";
        }
        Path filePath = Paths.get(strs[0], strs[1]);
        boolean bol = Files.exists(filePath);
        if (bol) {
            return strs;
        } else {
            return null;
        }
    }

    /**
     * @return 1：代理重启成功 2：进程未开启 3：进程关闭时出错 4：进程启动时出错
     */
    private int reStartAgentServer() {

        int flag = 0;
        if (findProcess()) {
            // 进程没开启
            try {
                killProc();
                startProc();
            } catch (Exception e) {
                e.printStackTrace();
                log.error("nginx.exe" + "线程开启失败");
            } finally {
                if (findProcess()) {
                    flag = 1;// 开启成功
                } else {
                    flag = 2;// 启动失败
                }
            }
        } else {
            try {
                startProc();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (findProcess()) {
                    flag = 1;// 开启成功
                } else {
                    flag = 2;// 启动失败
                }
            }
        }
        return flag;
    }

    /**
     * 关闭nginx进程
     *
     * @return 1：进程关闭成功 2：进程没有开启 3：进程关闭失败
     */
    private int stopAgentServer() {
        int flag = 0;

        if (findProcess()) {
            // 进程开启了
            try {
                killProc();
            } catch (Exception e) {
                e.printStackTrace();
                log.error("nginx.exe" + "线程关闭失败");
            } finally {
                if (!findProcess()) {
                    flag = 1;// 关闭成功
                } else {
                    flag = 3;// 关闭失败
                }
            }
        } else {
            // 进程没开启
            flag = 2;
        }
        return flag;

    }


    /**
     * 跨平台关闭nginx
     *
     * @throws IOException
     */
    private void killProc() throws Exception {
        if (OSCommandUtil.isWinOS()) {
            KillWin();
        } else {
            killLinuxProc();
        }
    }

    /**
     * 关闭windows系统的nginx
     *
     * @throws IOException
     */
    private void KillWin() throws IOException {
        executeCmdForWin("taskkill /F /IM " + "nginx.exe");
    }

    /**
     * @desc 执行cmd命令
     */
    private String executeCmdForWin(String command) throws IOException {
        Runtime runtime = Runtime.getRuntime();
        Process process = runtime.exec("cmd /c " + command);
        // Process process = runtime.exec( command);
        BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream(), "UTF-8"));
        String line = null;
        StringBuilder build = new StringBuilder();
        while ((line = br.readLine()) != null) {
            log.info(line);
            build.append(line);
        }
        return build.toString();
    }

    /**
     * @desc 执行cmd命令
     */
    private String executeCmdForLinux(String command) throws IOException {
        Runtime runtime = Runtime.getRuntime();
        Process process = runtime.exec(command);
        BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream(), "UTF-8"));
        String line = null;
        StringBuilder build = new StringBuilder();
        while ((line = br.readLine()) != null) {
            log.info(line);
            build.append(line);
        }
        return build.toString();
    }

    /**
     * @desc 判断进程是否开启
     */
    public boolean findProcess() {

        BufferedReader bufferedReader = null;
        String command = "";
        boolean running = false;
        try {
            if (OSCommandUtil.isWinOS()) {
                command = "tasklist -fi " + '"' + "imagename eq nginx.exe" + '"';
            } else {
                command = "ps aux|grep nginx";
            }
            Process proc = Runtime.getRuntime().exec(command);
            bufferedReader = new BufferedReader(new InputStreamReader(proc.getInputStream()));
            String line = null;
            int count = 0;
            while ((line = bufferedReader.readLine()) != null) {
                if (line.contains("nginx")) {
                    count++;
                }
            }
            if (OSCommandUtil.isWinOS()) {
                if (count >= 1) {
                    running = true;
                }
            } else {
                if (count >= 2) {
                    running = true;
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
            if (bufferedReader != null) {
                try {
                    bufferedReader.close();
                } catch (Exception ex) {
                }
            }
        }
        return running;
    }

    /**
     * 关闭linux系统的nginx
     *
     * @throws IOException
     */
    private void killLinuxProc() throws IOException {
        String command = "pkill -9 nginx";
        executeCmdForLinux(command);
    }

    /**
     * 打印进程的状态
     */
    private void logStatus() {
        boolean flag = findProcess();
        if (flag) {
            log.info("nginx.exe" + "进程状态：开启");
        } else {
            log.info("nginx.exe" + "进程状态：关闭");
        }
    }

    /**
     * 开启linux的nginx
     *
     * @throws IOException
     */
    private void startLinuxProc() throws Exception {
        log.info("开启代理进程");
        String[] agentServerPath = findAgentExeFile();
        if (agentServerPath != null && agentServerPath.length == 2) {
            String command1 = agentServerPath[0] + "/" + agentServerPath[1];

            String pro = executeCmdForLinux(command1);
            log.info(pro);
        } else {
            throw new Exception("未找到可执行文件");
        }

    }

    /**
     * windows平台开启
     *
     * @throws Exception 1：开启成功 2：开启失败 3：已开启
     */
    private int start() throws Exception {
        int flag = 0;

        if (!findProcess()) {
            // 进程开启了
            try {
                startProc();
            } catch (Exception e) {
            } finally {
                if (findProcess()) {
                    flag = 1;// 开启成功
                } else {
                    flag = 2;// 开启失败
                }
            }
        } else {
            // 进程已经开启
            flag = 3;
        }
        return flag;
    }


    /**
     * 开启windows系统的nginx
     *
     * @throws IOException
     */
    private void startWinProc() throws Exception {
        String agentExe = "cmd /c start nginx";
        String[] agentServerPaths = findAgentExeFile();
        if (agentServerPaths != null && agentServerPaths.length == 2) {
            String CONFPREFIXURL = agentServerPaths[0];

            File dir = new File(CONFPREFIXURL);
            String[] str = new String[]{};
            // 执行命令
            Runtime.getRuntime().exec(agentExe, str, dir);
        } else {
            throw new Exception("未找到启动文件");
        }
    }


    /**
     * 获取项目部署环境的ip
     *
     * @return
     */
    private String getIP() {
        String url = "";
        try {
            for (Enumeration<NetworkInterface> e = NetworkInterface.getNetworkInterfaces(); e.hasMoreElements(); ) {
                NetworkInterface item = e.nextElement();
                for (InterfaceAddress address : item.getInterfaceAddresses()) {
                    if (item.isLoopback() || !item.isUp()) {
                        continue;
                    }
                    if (address.getAddress() instanceof Inet4Address) {
                        Inet4Address inet4Address = (Inet4Address) address.getAddress();
                        url = inet4Address.getHostAddress();
                    }
                }
            }
            // url = InetAddress.getLocalHost().getHostAddress();
        } catch (SocketException e) {
            throw new RuntimeException(e);
        }
        return url;
    }

    /**
     * 判断某个字符串是否是数字
     *
     * @param str
     * @return
     */
    private boolean isNumer(String str) {
        for (int i = 0; i < str.length(); i++) {
            if (!Character.isDigit(str.charAt(i))) {
                return false;
            }
        }
        return true;
    }

    /**
     * 以行为单位读取文件，常用于读面向行的格式化文件
     *
     * @return
     */
    private int getPort() {
        String fileName = getConfAddr();
        int port = -1;
        File file = new File(fileName);
        BufferedReader reader = null;
        String lastLine = "";
        try {
            reader = new BufferedReader(new FileReader(file));
            String tempString = null;
            // 一次读入一行，直到读入null为文件结束
            while ((tempString = reader.readLine()) != null) {
                if (!tempString.trim().startsWith("#") && tempString.trim().length() != 0) {
                    // System.out.println(tempString.trim());
                    if ("server {".equals(lastLine.trim())) {
                        String content = tempString.trim();
                        if (content.startsWith("listen") && content.endsWith(";")) {
                            String number = content.replace("listen", "").replace(";", "").trim();
                            if (isNumer(number))
                                port = Integer.parseInt(number);
                        }
                    }
                    lastLine = tempString;
                }
            }
            reader.close();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e1) {
                }
            }
        }

        return port;
    }

    private String getConfAddr() {
        String CONFPREFIXURL = System.getProperty("user.dir") + File.separator + "nginx" + File.separator;
        if (OSCommandUtil.isWinOS()) {
            CONFPREFIXURL = CONFPREFIXURL + "windows" + File.separator + "conf" + File.separator + "agent-conf/nginx.conf";
        } else {
            // linux的处理
        }
        return CONFPREFIXURL;
    }

}
